#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/estep.c"

typedef struct _EstepTestDatum EstepTestDatum ;
struct _EstepTestDatum 
{ 
  struct
    {
      float     priorz[5];
      Rating    ratings[6];
      float     logalpha;
      float     loglambda[4];
      float     tau[4*(5-1)];
      int       clamp;
    }                   inputs;

  float pz[5];
};

static void
test_estep (void)
{
  EstepTestDatum data[] = 
    {{{{0.814949, 0.141617, 0.765801, 0.981022,  0.103446}, {{2, 0}, {2, 0}, {3, 4}, {0, 3}, {0, 4}, {2, 3}},  0.106636, {0.309478, 0.575298, 0.643435, 0.42637}, {0.166957,  0.151918, 0.119927, 0.107642, 0.103735, 0.157737, 0.0435579,  0.0496985, 0.0944192, 0.07914, 0.0588389, 0.0265666, 0.0502174,  0.0666261, 0.095849, 0.198243}, -1}, {7.19003e-12, 0.00015413,  0.938327, 0.0615189,  6.13687e-8}}, {{{0.352108, 0.3758, 0.884581, 0.175808,  0.77681}, {{3, 4}, {2, 1}, {0, 2}, {2, 4}, {3, 4}, {3, 4}},  0.732364, {0.45821, 0.341021, 0.01722, 0.132729}, {0.184, 0.164469,  0.0457068, 0.182988, 0.134302, 0.07005, 0.166567, 0.124149,  0.107735, 0.0198326, 0.0999407, 0.0283001, 0.109492, 0.122775,  0.0295191, 0.15314}, 3}, {2.46502e-38, 1.20675e-21,  9.99667e-11, 1.,  1.10816e-7}}, {{{0.438069, 0.370785, 0.0333366, 0.204668,  0.0970484}, {{3, 0}, {2, 4}, {3, 1}, {1, 2}, {2, 4}, {3, 0}},  0.353565, {0.900607, 0.284668, 0.274702, 0.125031}, {0.197133,  0.122632, 0.18489, 0.0584394, 0.0729843, 0.0148969, 0.165058,  0.158499, 0.0446841, 0.105405, 0.0422823, 0.12898, 0.0915439,  0.172829, 0.154668, 0.0548225}, -1}, {3.42489e-9, 0.00491883,  0.982914, 0.0121677,  9.54924e-9}}, {{{0.659479, 0.676294, 0.920548, 0.523776,  0.374811}, {{3, 3}, {2, 1}, {1, 1}, {0, 4}, {3, 4}, {3, 4}},  0.401592, {0.795516, 0.538109, 0.761652, 0.47714}, {0.100664,  0.0346375, 0.137433, 0.13037, 0.142165, 0.189953, 0.0320284,  0.0880878, 0.0131857, 0.0984094, 0.0591989, 0.133419, 0.158363,  0.0135328, 0.127303, 0.198161}, 2}, {2.59532e-32,  5.04024e-16, 0.998512, 0.00148816,  2.86467e-7}}, {{{0.543888, 0.261704, 0.589211, 0.0757518,  0.00577961}, {{3, 4}, {0, 4}, {0, 4}, {2, 1}, {2, 1}, {3, 4}},  0.500053, {0.112071, 0.572432, 0.832592, 0.812885}, {0.0920441,  0.172321, 0.176565, 0.130549, 0.00395623, 0.159135, 0.0781557,  0.0713497, 0.0705369, 0.000772331, 0.0646228, 0.144047, 0.0723764,  0.0265187, 0.155845, 0.0917057}, 4}, {1.71588e-34,  6.94317e-16, 0.000048927, 0.0780182,  0.921933}}, {{{0.0568417, 0.773446, 0.958476, 0.6606,  0.484409}, {{0, 1}, {1, 3}, {2, 0}, {2, 0}, {3, 2}, {2, 0}},  0.940854, {0.145591, 0.20038, 0.622804, 0.0580286}, {0.0985694,  0.0361198, 0.165425, 0.13345, 0.0272197, 0.165583, 0.164653,  0.0688272, 0.0831731, 0.0932065, 0.138134, 0.112982, 0.191467,  0.138672, 0.126766, 0.158293}, 3}, {0.000718631, 0.999281,  4.75068e-7, 1.73897e-17,  4.0191e-49}}, {{{0.032761, 0.14942, 0.85061, 0.853271,  0.832381}, {{3, 1}, {3, 3}, {0, 1}, {3, 0}, {1, 2}, {2, 1}},  0.526616, {0.792581, 0.360424, 0.651782, 0.69949}, {0.0250662,  0.0448651, 0.164774, 0.175245, 0.156239, 0.161692, 0.0715671,  0.0371109, 0.043257, 0.170224, 0.132895, 0.110345, 0.0849642,  0.170452, 0.126343, 0.0804611}, 1}, {2.64344e-13, 0.999999,  5.80936e-7, 4.10124e-16,  9.92762e-34}}, {{{0.99899, 0.799332, 0.875689, 0.781629,  0.638566}, {{1, 0}, {2, 2}, {2, 4}, {0, 1}, {0, 1}, {3, 3}},  0.14755, {0.176199, 0.656298, 0.41424, 0.323682}, {0.0599946,  0.175021, 0.121156, 0.193169, 0.0228837, 0.131764, 0.150932,  0.0602745, 0.112539, 0.0467996, 0.18048, 0.133932, 0.0320776,  0.131957, 0.180682, 0.174066}, -1}, {1.34476e-7, 0.0188507,  0.978102, 0.00304684,  1.09685e-9}}, {{{0.878158, 0.264843, 0.722778, 0.1085,  0.221859}, {{3, 4}, {3, 3}, {1, 1}, {2, 1}, {2, 4}, {0, 2}},  0.850602, {0.399096, 0.808527, 0.346756, 0.244821}, {0.0866498,  0.138822, 0.137587, 0.0980326, 0.0263753, 0.0262831, 0.0907879,  0.117553, 0.0924434, 0.194205, 0.15883, 0.136871, 0.118378,  0.137266, 0.183199, 0.0839028}, 1}, {5.93966e-27, 0.000429091,  0.658414, 0.341157,  1.06283e-10}}, {{{0.577828, 0.694135, 0.568912, 0.470016,  0.769301}, {{3, 0}, {0, 2}, {3, 1}, {3, 4}, {3, 3}, {2, 1}},  0.34738, {0.32409, 0.0367669, 0.0751924, 0.659442}, {0.166786,  0.180978, 0.188755, 0.0411006, 0.0492325, 0.0885347, 0.19455,  0.0822702, 0.112361, 0.170157, 0.0572842, 0.0990712, 0.0284584,  0.196334, 0.141719, 0.160244}, 1}, {6.81143e-15, 0.993793,  0.00619782, 9.07417e-6, 1.40415e-14}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      float pz[5];

      for (unsigned int j = 0; j < 5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.logalpha,
             5,
             data[i].inputs.tau,
             data[i].inputs.loglambda,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             6);

      for (unsigned int j = 0; j < 5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  5e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 1));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_estep ();

  return 0;
}
